package com.example.shirodemo.controller;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.example.shirodemo.constant.HttpCode;
import com.example.shirodemo.dto.ResponseResult;
import com.example.shirodemo.entity.SUser;
import com.example.shirodemo.pojo.User;
import com.example.shirodemo.service.UserService;
import com.example.shirodemo.utils.CommonUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.SavedRequest;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author 绫小路
 * @date 2021/1/10 18:07
 * @description
 */
@Api(tags="01-账户相关操作：登录、注册等：AccountController")
@Slf4j
@Controller
public class AccountController {


  @Autowired
  private HttpServletRequest request;
  @Autowired
  private UserService userService;

  @ApiOperation("登录页面")
  @GetMapping("login")
  public String login() {
    request.setAttribute("referer", request.getHeader("Referer"));
    return "login";
  }

  //我们不使用shiro的密码认证，在此验证
  //自己认证， 账号密码认证 采用 MD5 + 随机盐salt
  //密码加密方式：密码第二位插入盐 再md5加密，例如密码是123，盐是Po*-，那么加盐后是1Po*-23 再md5
  @ApiOperation("登录")
  @PostMapping("login")
  @ResponseBody
  public ResponseResult login(String username, String password) {
    Assert.notBlank(username, "账号不能为空！");
    Assert.notBlank(username, "密码不能为空！");
    try {
      //查询数据库
      SUser user = userService.getUserByUsername(username);
      if (user == null) {
        throw new UnknownAccountException("账号不存在");
      }
      if (user.getStatus() != 1) {
        return new ResponseResult(HttpCode.FAIL, "当前账号无效或被停止使用！");
      }
      if (!CommonUtils.passwordToMD5(password, user.getSalt()).equals(user.getPassword())) {
        throw new IncorrectCredentialsException("密码错误！");
      }

      //通过安全工具类获取主体，初始化时自定注入了
      Subject subject = SecurityUtils.getSubject();
      //创建token
      UsernamePasswordToken token = new UsernamePasswordToken(username, password);
      subject.login(token);
      //信息存会话中
      User info = new User();
      info.setId(user.getId());
      info.setUsername(user.getUsername());
      info.setNickname(user.getNickname());
      request.getSession().setAttribute("user", info);
    } catch (UnknownAccountException e) {
      log.error("账号不存在！");
      return new ResponseResult(HttpCode.FAIL, e.getMessage());
    } catch (IncorrectCredentialsException e) {
      log.error("无效的凭据，密码错误！");
      return new ResponseResult(HttpCode.FAIL, "无效的凭据，密码错误！");
    } catch (LockedAccountException e) {
      log.error("当前账号被锁定，无法登录");
      return new ResponseResult(HttpCode.FAIL, "当前账号被锁定，无法登录");
    } catch (AuthenticationException e) {
      log.error("授权过程中的异常：{}", e.getMessage());
      return new ResponseResult(HttpCode.FAIL, "登录异常" + e.getMessage());
    }

    //登录后，返回原访问页面
    SavedRequest savedRequest = WebUtils.getSavedRequest(request);
    if (savedRequest != null) {
      // 登录前url
      return new ResponseResult(HttpCode.OK, "登录成功！", savedRequest.getRequestUrl());
    }
    String referer = request.getParameter("referer");
    if (StrUtil.isBlank(referer)) {
      referer = "/";
    } else if (referer.contains("/register")) {
      referer = "/";
    }
    return new ResponseResult(HttpCode.OK, "登录成功！", referer);
  }

  @ApiOperation("注销当前账号")
  @GetMapping("logout")
  public String logout() {
    //通过安全工具类获取主体，初始化时自定注入了
    Subject subject = SecurityUtils.getSubject();
    subject.logout();
    //重定向到登录
    return "redirect:/login";
  }

  @ApiOperation("注册账号页面")
  @GetMapping("register")
  public String register() {
    return "register";
  }

  @ApiOperation("注册账号")
  @PostMapping("register")
  @ResponseBody
  public ResponseResult register(String username, String password, String nickname) {
    if (StrUtil.isBlank(username)) {
      return new ResponseResult(HttpCode.FAIL, "账号不能为空！");
    }
    if (username.length() < 3) {
      return new ResponseResult(HttpCode.FAIL, "账号长度不能小于3 ！");
    }
    Assert.isFalse(username.length() > 21, "账号长度不能大于21");
    if (StrUtil.isBlank(password)) {
      return new ResponseResult(HttpCode.FAIL, "密码不能为空！");
    }
    Assert.isFalse(password.length() > 21, "密码长度不能大于21");
    if (StrUtil.isBlank(nickname)) {
      return new ResponseResult(HttpCode.FAIL, "昵称不能为空！");
    }
    Assert.isFalse(nickname.length() > 12, "昵称长度不能大于12");
    return userService.register(username, password, nickname);
  }

}
